#!/usr/bin/python
'''
Created on 2009-4-2

@author: QinPing He
'''
import socket,time,re
from com.carnation.qa.socketserver.common.util import Comparer
class parserItem:
    def __init__(self, cmd, parameter):
        self.name=cmd
        self.value=parameter
        self.isList=False
        
    def setList(self):
        self.isList=True
    
    def __str__(self):
        return "(%s,%s,%s)"%(self.name,self.value,self.isList)

    def __repr__(self): 
        return "parserItem(%s,%s,%s)"%(self.name,self.value,self.isList)
    
    def islist(self):
        return self.isList
    
class testTools:
    
    def __init__(self, sciptFileFile, IPAddress='127.0.0.1', port=10000, rspTimeOut=120, intevalTimeout=1):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((IPAddress, port))
        self.sock.setblocking(True)
        self.rspTimeOut=rspTimeOut
        self.intevalTimeout=intevalTimeout
        self.__setTimeOut(self.rspTimeOut)
        self.patter=re.compile(r"(    |\t)*(\w+)(    |\t)?(.*)")
        self.logfile= open(sciptFileFile+'.log', 'a')
        self.log('Run testcase<: ' + sciptFileFile + ' >')
    
    def log(self, logStr):
        self.logfile.write(logStr)
        self.logfile.write('\n')
        
    def __setTimeOut(self, time):
        self.socket_timeout=time
        self.sock.settimeout(time)
    
    def __getTimeOut(self):
        return self.socket_timeout
    
    def writeMsg(self, s):
        self.sock.setblocking(True)
        length = len(s)
        s1p=chr(length>>24& 0xff)
        s1p+=chr(length>>16& 0xff)
        s1p+=chr(length>>8& 0xff)
        s1p+=chr(length& 0xff)
        if length>0:
            s1p+=s
        self.sock.send(s1p)
        
    def recv_timeout(self, length):
        timeout=self.__getTimeOut()
        self.sock.setblocking(False)
        response_data=''
        data=''
        begin=time.time()
        i=0
        try:
            while i<length:
                #if you got some data, then break after wait sec
                if response_data and time.time()-begin>timeout:
                    raise socket.timeout('timeout')
                #if you got no data at all, wait a little longer
                elif time.time()-begin>timeout:
                    raise socket.timeout('timeout')
                try:
                    data=self.sock.recv(length-i)
                    if data:
                        i=i+len(data)
                        response_data=response_data+data
                        begin=time.time()
                    else:
                        time.sleep(0.1)
                except socket.error, e:
#                    print e[0],e[1]
                    if e[0]==socket.errno.EWOULDBLOCK:
                        pass
                    else:
                        raise e
            return response_data
        finally:
            self.sock.setblocking(True)
            self.__setTimeOut(timeout)
            

    def recvMsg(self):
        try:
            header=self.recv_timeout(4)
            length = ord(header[0]) << 24 |ord(header[1]) << 16 |ord(header[2]) << 8 |ord(header[3])
            msg = self.recv_timeout(length)
            return msg
        except socket.timeout, e:
#            print e
            return ''
    
    def quit(self):
        self.sock.close()
        self.log("done")
        self.logfile.close()
    
    def parseString(self, inString):
        if inString is None:
            return None 
        outS = inString.split('\n')
        recordStack=[]
        
        cmdString=None
        LineNumber=0
        for i in outS:
            LineNumber=LineNumber+1
            ###"(    |\t)*(\w+)(    |\t)?(.*)"###
            m=self.patter.match(i)
            if m is None:
                i1=i.strip()
                if (i1 is None) or (i1=='') :
                    continue
                raise 'Format Error near:at(' + str(LineNumber) +')>>' + i
            aa = m.groups()
            #get 0,1
            tabString=aa[0]
            requestString=aa[1]
            if tabString is not None:
                b = i.find(requestString)
                c = len(tabString)
                k1=b/c

                ListNum=0
                for i1 in range(min(k1, len(recordStack))):
                    item=recordStack[i1]
                    if item.islist():
                        ListNum=ListNum+1
                k=k1-ListNum
                     
                if len(recordStack)<k-1:
                    raise 'Format Error near:at(' + str(LineNumber) +')>>' + i
                   
                if k<len(recordStack):
                    if ListNum>0:
                        del recordStack[k+1:]
                    else:
                        del recordStack[k:]
                kkk =recordStack[k-1]
                if aa[2] is None:
                    if aa[1].isdigit():
                        if ListNum>0 and kkk.islist():
                            newMap={}
                            kkk1=recordStack[k]
                            kkk.value[kkk1.name].append(newMap)
                            kkk1.value=newMap
                        else:
                            if ListNum>0 and k<len(recordStack):
                                k=k+1
                                kkk =recordStack[k-1]
                            newMap={}
                            kkk2=recordStack[k-2]
                            newList=kkk2.value[kkk.name]
                            if not isinstance(newList,list):
                                newList=[]
                                kkk2.value[kkk.name]=newList
                            newList.append(newMap)
                            kkk.value=newMap
                            kkk.setList()
                    else:
                        newMap={}
#                   self.name=name
#                   self.value=value
                        kkk.value[requestString]=newMap
                        item=parserItem(requestString, newMap)
                        recordStack.append(item)
                else:
                    if aa[1].isdigit() and aa[3]=='_':
                        if ListNum>0 and kkk.islist():
                            kkk1=recordStack[k]
                            kkk.value[kkk1.name].append(aa[2])
                        else:
                            if ListNum>0 and k<len(recordStack):
                                k=k+1
                                kkk =recordStack[k-1]
                            kkk2=recordStack[k-2]
                            newList=kkk2.value[kkk.name]
                            if not isinstance(newList,list):
                                newList=[]
                                kkk2.value[kkk.name]=newList
                            newList.append(aa[3])
                            kkk.value=aa[3]
                            kkk.setList()
                    else:
                        if not isinstance(kkk.value, dict):
                            raise 'Format Error near:at(' + str(LineNumber) +')>>' + i
                        v=kkk.value.get(requestString)
                        if isinstance(v, list):
                            newMap={}
                            v.append(newMap)
                        else:
                            kkk.value[requestString]=aa[3]
            else:
                    if cmdString is not None:
                        raise 'Format Error near:at(' + str(LineNumber) +')>>' + i
                    cmdString=requestString
                    item=parserItem(cmdString,{})
                    recordStack.append(item)
        return recordStack[0]

    def compare(self, expectObj, outObj):
    #
    #    input parameter:    @param expectObj
    #    input parameter:    @param outObj
    #
        if expectObj is None:
            return outObj is None;
        else:
            if isinstance(expectObj, str):
                if isinstance(outObj, str):
                    return expectObj==outObj
            elif isinstance(expectObj, dict):
                if isinstance(outObj, dict):
                    for i in expectObj.keys():
                        valueExpect=expectObj[i]
                        if valueExpect=='_':
                            continue;
                        valueO=outObj.get(i)
                        if valueO is None:
                            return False
                        r1 = self.compare(valueExpect, valueO)
                        if not r1:
                            return False
                else:
                    return False
            elif isinstance(expectObj, list):
                if isinstance(outObj, list):
                    if len(expectObj)!=len(outObj):
                        return False
                    for i in range(len(expectObj)):
                        valueExpect=expectObj[i]
                        if valueExpect=='_':
                            continue;
                        valueO=outObj[i]
                        if valueO is None:
                            return False
                        r1 = self.compare(valueExpect, valueO)
                        if not r1:
                            return False
        return True
        
    def diff(self, expectedString, outString):
        if expectedString is None:
            if outString is None:
                return False
            else:
                if len(outString)==0:
                    return True
                return False
        else:
            #    call java class to compare strings.
            c = Comparer()
            result = c.diff(expectedString, outString)
            self.log(outString)
            if result == 1:
    #            self.log("Run success" )
                return False
            else:
    #            self.log("Run success" )
                return True


#        result = True
#        if isinstance(expectedString, str): 
#            itemOut = self.parseString(outString)
#            itemExpect = self.parseString(expectedString)
#            if itemOut.name==itemExpect.name:
#                result=self.compare(itemExpect.value,itemOut.value)
#            else:
#                result=False
#
#            if not result:
#                return False
#            else:
#                self.log(outString)
#                self.log("Run success" )
#        elif isinstance(expectedString, list):
#            if not isinstance(outString, list):
#                return False
#            for i in range(min(len(expectedString), len(outString))):
#                itemOut = self.parseString(outString[i])
#                itemExpect = self.parseString(expectedString[i])
#                if itemOut.name==itemExpect.name:
#                    result=self.compare(itemExpect.value, itemOut.value)
#                else:
#                    result=False
#                if not result:
#                    return False
#        elif expectedString is None:
#            if outString is None:
#                return False
#            else:
#                if len(outString)==0:
#                    return True
#                return False
#        else:
#            return False
#        return True

    def requestAndRsp(self, step, comment, reques, expect_rsp, expect_EventMsg=None):
        import types
        try:
            self.log('\n' + '*'*80 )
            self.log('\nRun Step:' + str(step))
            self.log(comment)
            self.log("request Message:")
            self.log(reques)
            self.log("expect Message:")
            self.log(expect_rsp)
            self.writeMsg(reques)
            self.log("response Message:")
            self.__setTimeOut(self.rspTimeOut)
            response_data=''
            expectMsgList=[]
            if reques!=None:
                response_data = self.recvMsg()
                self.__setTimeOut(self.intevalTimeout)

                while 1:
                    event_data = self.recvMsg()
                    if event_data=='':
                        break
                    expectMsgList.append(event_data)
                    if( self.__getTimeOut()!=self.intevalTimeout):
                        self.__setTimeOut(self.intevalTimeout)

            import java
            ret = self.diff(expect_rsp, response_data)
            if not ret:
                self.log("Run Faile" )
                java.lang.System.out.print("X")
                return ''
            ret = self.diff(expect_EventMsg, expectMsgList)
            if not ret:
                self.log("Run Faile" )
                java.lang.System.out.print("X")
                return ''
            
            java.lang.System.out.print(".")
            self.log("Run Success" )
            return response_data;
        except IOError, e:
            raise e
        except Exception, e:
            print 'Execption raised:', e
            return ''
        
if __name__ == '__main__':
    test = testTools(__file__) 
    
    rsp_msg=test.requestAndRsp(1, 'Run For Test afdsafsdfsf',   \
'''
createMO
    inputMO
        valueList
            0
                aaa    bbb
                kkk
                    0
                        cc    adssad
            1
                ddd    eee
        name    test
        value    aaa''',    \
'''
createMO
    inputMO
        valueList
            0
                aaa    bbb1
                kkk
                    0
                        cc    adssad
            1    _
        name    _
        value    aaa'''
)
#    print rsp_msg
    print '\nDone'
    test.quit()
